package com.example.apitesttool.service;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.parser.OpenAPIV3Parser;
import io.swagger.v3.parser.core.models.ParseOptions;
import io.swagger.v3.parser.core.models.SwaggerParseResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Swagger/OpenAPI 文档处理服务
 * 
 * 负责处理 OpenAPI/Swagger 文档的解析、验证、存储和格式化。
 * 提供文档的业务逻辑处理，包括从文件和 URL 导入文档。
 * 
 * 主要功能：
 * - OpenAPI 文档解析和验证
 * - 文档格式化和信息提取
 * - 文档存储和管理
 * - 系统状态统计
 * - URL 导入支持
 * 
 * @author liuxy
 * @version 1.0.0
 */
@Service
public class SwaggerService {
    
    private static final Logger logger = LoggerFactory.getLogger(SwaggerService.class);
    
    @Autowired
    private OpenApiDocumentManager documentManager;
    
    @Autowired
    private DocumentVectorizationService documentVectorizationService;

    /**
     * 处理并存储上传的 Swagger/OpenAPI 文档
     * 
     * @param swaggerContent 文档的 JSON/YAML 字符串内容
     * @param originalFilename 原始文件名（可选，用于日志记录）
     * @return 包含文档ID和格式化输出的Map
     * @throws Exception 如果文档解析失败
     */
    public Map<String, String> processAndStoreSwagger(String swaggerContent, String originalFilename) throws Exception {
        logger.info("开始处理 OpenAPI 文档，原始文件名: {}", originalFilename);
        
        if (swaggerContent == null || swaggerContent.trim().isEmpty()) {
            throw new IllegalArgumentException("文档内容不能为空");
        }
        
        // 解析 OpenAPI 文档
        OpenAPI openAPI = parseOpenApiDocument(swaggerContent);
        
        // 验证文档的基本结构
        validateOpenApiDocument(openAPI);
        
        // 存储文档到文档管理器
        String documentId = documentManager.storeDocument(openAPI);
        
        // 向量化文档
        try {
            documentVectorizationService.vectorizeDocument(documentId);
            logger.info("文档 {} 向量化完成", documentId);
        } catch (Exception e) {
            logger.warn("文档向量化失败，但文档已成功存储: {}", e.getMessage());
        }
        
        // 生成格式化输出
        String formattedOutput = formatOpenApiDocument(openAPI, documentId);
        
        logger.info("OpenAPI 文档处理完成，文档 ID: {}", documentId);
        
        Map<String, String> result = new HashMap<>();
        result.put("specId", documentId);
        result.put("formattedOutput", formattedOutput);
        return result;
    }

    /**
     * 从 URL 处理并存储 Swagger/OpenAPI 文档
     * 
     * @param url 文档的 URL 地址
     * @return 包含文档ID和格式化输出的Map
     * @throws Exception 如果文档下载或解析失败
     */
    public Map<String, String> processAndStoreSwaggerFromUrl(String url) throws Exception {
        logger.info("开始从 URL 下载 OpenAPI 文档: {}", url);
        
        if (url == null || url.trim().isEmpty()) {
            throw new IllegalArgumentException("URL 不能为空");
        }
        
        // 下载文档内容
        String content = downloadContentFromUrl(url);
        
        // 处理下载的内容
        return processAndStoreSwagger(content, "从 URL 导入: " + url);
    }

    /**
     * 获取系统状态和统计信息
     * 
     * @return 系统状态信息
     */
    public Map<String, Object> getSystemStatus() {
        Map<String, Object> status = new HashMap<>();
        
        // 基本统计信息
        status.put("totalDocuments", documentManager.getDocumentCount());
        status.put("activeDocumentId", documentManager.getCurrentActiveDocumentId().orElse(null));
        
        // 文档列表
        List<OpenApiDocumentManager.DocumentMetadata> allMetadata = documentManager.getAllDocumentMetadata();
        status.put("documents", allMetadata);
        
        // 向量数据库统计
        try {
            Map<String, Object> vectorStats = documentVectorizationService.getVectorizationStats();
            status.put("vectorDatabase", vectorStats);
        } catch (Exception e) {
            logger.warn("获取向量数据库统计信息失败: {}", e.getMessage());
        }
        
        // 系统信息
        status.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        status.put("status", "运行中");
        
        logger.debug("生成系统状态信息，当前文档数量: {}", documentManager.getDocumentCount());
        return status;
    }

    /**
     * 解析 OpenAPI 文档字符串
     * 
     * @param content 文档内容
     * @return 解析后的 OpenAPI 对象
     * @throws IllegalArgumentException 如果解析失败
     */
    private OpenAPI parseOpenApiDocument(String content) throws IllegalArgumentException {
        try {
            ParseOptions options = new ParseOptions();
            options.setResolve(true); // 解析引用
            options.setResolveFully(true); // 完全解析
            
            SwaggerParseResult result = new OpenAPIV3Parser().readContents(content, null, options);
            
            // 检查解析错误
            if (result.getMessages() != null && !result.getMessages().isEmpty()) {
                logger.warn("OpenAPI 文档解析时出现警告: {}", result.getMessages());
            }
            
            OpenAPI openAPI = result.getOpenAPI();
            if (openAPI == null) {
                throw new IllegalArgumentException("无法解析 OpenAPI 文档。请检查文档格式是否正确。可能的原因：\n" +
                    "1. JSON/YAML 语法错误\n" +
                    "2. 不符合 OpenAPI 规范\n" +
                    "3. 缺少必要的字段（如 openapi 版本声明）");
            }
            
            logger.debug("OpenAPI 文档解析成功");
            return openAPI;
            
        } catch (Exception e) {
            logger.error("解析 OpenAPI 文档时发生错误", e);
            throw new IllegalArgumentException("解析 OpenAPI 文档失败: " + e.getMessage(), e);
        }
    }

    /**
     * 验证 OpenAPI 文档的基本结构
     * 
     * @param openAPI 要验证的 OpenAPI 对象
     * @throws IllegalArgumentException 如果验证失败
     */
    private void validateOpenApiDocument(OpenAPI openAPI) throws IllegalArgumentException {
        if (openAPI.getInfo() == null) {
            throw new IllegalArgumentException("OpenAPI 文档缺少 'info' 部分，这是必需的");
        }
        
        Info info = openAPI.getInfo();
        if (info.getTitle() == null || info.getTitle().trim().isEmpty()) {
            logger.warn("OpenAPI 文档的标题为空，将使用默认标题");
            info.setTitle("未命名 API");
        }
        
        if (info.getVersion() == null || info.getVersion().trim().isEmpty()) {
            logger.warn("OpenAPI 文档的版本为空，将使用默认版本");
            info.setVersion("1.0.0");
        }
        
        if (openAPI.getPaths() == null || openAPI.getPaths().isEmpty()) {
            logger.warn("OpenAPI 文档没有定义任何路径，这可能不是一个有效的 API 文档");
        }
        
        logger.debug("OpenAPI 文档验证通过");
    }

    /**
     * 格式化 OpenAPI 文档为用户友好的字符串
     * 
     * @param openAPI OpenAPI 对象
     * @param documentId 文档 ID
     * @return 格式化的字符串
     */
    private String formatOpenApiDocument(OpenAPI openAPI, String documentId) {
        StringBuilder formatted = new StringBuilder();
        
        formatted.append("📄 **OpenAPI 文档上传成功**\n\n");
        formatted.append("**文档 ID:** `").append(documentId).append("`\n\n");
        
        // 基本信息
        Info info = openAPI.getInfo();
        if (info != null) {
            formatted.append("**基本信息:**\n");
            formatted.append("- **标题:** ").append(info.getTitle()).append("\n");
            formatted.append("- **版本:** ").append(info.getVersion()).append("\n");
            if (info.getDescription() != null && !info.getDescription().trim().isEmpty()) {
                formatted.append("- **描述:** ").append(info.getDescription()).append("\n");
            }
            formatted.append("\n");
        }
        
        // 服务器信息
        if (openAPI.getServers() != null && !openAPI.getServers().isEmpty()) {
            formatted.append("**服务器地址:**\n");
            openAPI.getServers().forEach(server -> {
                formatted.append("- ").append(server.getUrl());
                if (server.getDescription() != null) {
                    formatted.append(" (").append(server.getDescription()).append(")");
                }
                formatted.append("\n");
            });
            formatted.append("\n");
        }
        
        // 接口统计
        if (openAPI.getPaths() != null) {
            int pathCount = openAPI.getPaths().size();
            int operationCount = calculateOperationCount(openAPI);
            
            formatted.append("**接口统计:**\n");
            formatted.append("- **路径数量:** ").append(pathCount).append("\n");
            formatted.append("- **操作数量:** ").append(operationCount).append("\n\n");
            
            // 接口列表
            if (pathCount > 0) {
                formatted.append("**接口列表:**\n");
                openAPI.getPaths().forEach((path, pathItem) -> {
                    formatted.append("- **").append(path).append("**\n");
                    
                    pathItem.readOperationsMap().forEach((httpMethod, operation) -> {
                        formatted.append("  - `").append(httpMethod.name()).append("` ");
                        if (operation.getSummary() != null) {
                            formatted.append(operation.getSummary());
                        } else {
                            formatted.append("无描述");
                        }
                        formatted.append("\n");
                    });
                });
                formatted.append("\n");
            }
        }
        
        // 组件信息
        if (openAPI.getComponents() != null) {
            if (openAPI.getComponents().getSchemas() != null && !openAPI.getComponents().getSchemas().isEmpty()) {
                formatted.append("**数据模型:** ").append(openAPI.getComponents().getSchemas().size()).append(" 个\n");
            }
            if (openAPI.getComponents().getSecuritySchemes() != null && !openAPI.getComponents().getSecuritySchemes().isEmpty()) {
                formatted.append("**安全方案:** ").append(openAPI.getComponents().getSecuritySchemes().size()).append(" 个\n");
            }
        }
        
        formatted.append("\n✅ 文档已成功解析并存储，可以开始进行接口测试了！");
        
        return formatted.toString();
    }

    /**
     * 计算 OpenAPI 文档中的操作总数
     * 
     * @param openAPI OpenAPI 对象
     * @return 操作总数
     */
    private int calculateOperationCount(OpenAPI openAPI) {
        if (openAPI.getPaths() == null) {
            return 0;
        }
        
        int count = 0;
        for (PathItem pathItem : openAPI.getPaths().values()) {
            count += pathItem.readOperationsMap().size();
        }
        return count;
    }

    /**
     * 从 URL 下载内容
     * 
     * @param urlString URL 地址
     * @return 下载的内容
     * @throws Exception 如果下载失败
     */
    private String downloadContentFromUrl(String urlString) throws Exception {
        logger.debug("开始从 URL 下载内容: {}", urlString);
        
        URL url = new URL(urlString);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        
        try {
            // 设置请求属性
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(10000); // 10秒连接超时
            connection.setReadTimeout(30000);    // 30秒读取超时
            connection.setRequestProperty("User-Agent", "API-Test-Tool/1.0");
            connection.setRequestProperty("Accept", "application/json, application/yaml, text/yaml, text/plain");
            
            // 检查响应码
            int responseCode = connection.getResponseCode();
            if (responseCode != HttpURLConnection.HTTP_OK) {
                throw new Exception("HTTP 请求失败，响应码: " + responseCode + " " + connection.getResponseMessage());
            }
            
            // 读取响应内容
            StringBuilder content = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    content.append(line).append("\n");
                }
            }
            
            String result = content.toString();
            logger.debug("从 URL 下载内容成功，长度: {} 字符", result.length());
            
            if (result.trim().isEmpty()) {
                throw new Exception("从 URL 下载的内容为空");
            }
            
            return result;
            
        } finally {
            connection.disconnect();
        }
    }
}

